package com.kalvan.web.servlet.interceptor;

import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kalvan.client.context.RequestContext;
import com.kalvan.client.context.RequestContextHolder;
import com.kalvan.log.logback.layout.converter.ExtJsonConverter;
import com.kalvan.log.logback.layout.converter.LogTraceIdConverter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 进行接口耗时、接口请求频率统计限制等统计和拦截
 *
 * @author chenliang
 * @version 2018年11月8日
 */
@Slf4j
public class CallInterfaceInterceptor extends HandlerInterceptorAdapter {
    static final String IGNORED_TRACE = "Ignored_Trace" ;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        //初始化context
        RequestContext context = new RequestContext();
        RequestContextHolder.setContext(context);
        //设置调用时间
        context.setStartTime(System.currentTimeMillis());
        //设置日志戳
        LogTraceIdConverter.resetLogTraceId();
        String logTraceId = TraceContext.traceId();
        if (StringUtils.isNotBlank(logTraceId) && !IGNORED_TRACE.equals(logTraceId)) {
            //使用SkyWalking链路日志戳
            LogTraceIdConverter.setLogTraceId(logTraceId);
        }
        String ip = ServletUtil.getClientIP(request);
        String path = request.getRequestURI();
        context.setService(path);
        context.setSourceIp(ip);
        context.setLogTraceId(LogTraceIdConverter.getCurrentLogTraceId());
        log.info("请求地址:{}, ip:{}", path, ip);
        if (!request.getParameterMap().isEmpty()) {
            log.info("请求参数:{}", JSON.toJSONString(request.getParameterMap()));
            context.setAppId(request.getParameter("appId"));
        } else {
            String body = ServletUtil.getBody(request);
            if (JSONUtil.isJsonObj(body)) {
                context.setAppId(JSONObject.parseObject(body).getString("appId"));
            }
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        RequestContext context = RequestContextHolder.getContext();
        context.setEndTime(System.currentTimeMillis());
        //注入ext日志埋点
        JSONObject object = new JSONObject();
        object.put("request_service", context.service);
        object.put("response_time", context.endTime - context.startTime);
        if (StringUtils.isNotBlank(context.appId)) {
            object.put("appId", context.appId);
        }
        if (StringUtils.isNotBlank(context.responseCode)) {
            object.put("response_code", context.responseCode);
        }
        if (StringUtils.isNotBlank(context.responseDesc)) {
            object.put("response_desc", context.responseDesc);
        }
        ExtJsonConverter.setExtJson(object.toJSONString());
        //打一行空日志将extJson埋点进去
        log.info("");
        ExtJsonConverter.resetExtJson();
        //清除context
        RequestContextHolder.remove();
        //清除日志戳
        LogTraceIdConverter.resetLogTraceId();
    }
}
